<?php

namespace App\Models\Order;

use App\Models\Options\Option;
use App\Models\Setting;
use App\Services\Locale\Language;
use App\Services\MobileApp\AppEnv;
use App\Services\Utils\Guard;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;

/**
 * @property int customer_id
 * @property int $order_id
 * @property int $order_status_id
 * @property string payment_code - 支付插件代码
 * @property string total - 总价
 * @property string store_name
 * @property string $trade_no
 * @property string payment_fullname
 * @property string currency_code
 * @property string ip
 * @property-read Collection|OrderProduct[] orderProducts
 * @property-read Collection|OrderTotal[] orderTotals
 * @property-read OrderTotal orderTotalByTotal
 * @property-read OrderStatus orderStatusByLanguage
 * @property-read OrderHistory orderHistoryByPayment
 * @property-read OrderAutoSign orderAutoSign
 * @property-read int expire_date
 * @property string comment
 * @property string shipping_method
 * @property string payment_method
 * @property string date_added
 * @property string shipping_code
 * @property string shipping_shipper_code
 * @property string shipping_logistic_code
 * @property string shipping_country_id
 * @property string shipping_zone_id
 * @property OrderHistory orderHistoryByComplete
 *
 * @method static self filterOrderStatusIds($order_status_id)
 * @method static self filterIsToBeEvaluate($order_flow_status_id)
 * @method static self filterCancelOrder()
 * @method static self filterLogistics()
 *
 * @mixin Builder
 */
class Order extends Model
{
    const ACCEPT_LANGUAGE_DEFAULT = 'zh-CN,zh;q=0.9,en;q=0.8';
    const AFFILIATE_ID_DEFAULT = 0;
    const STATUS_ID_DEFAULT = 0;
    const COMMISSION_DEFAULT = 0.000;
    const MARKETING_ID_DEFAULT = 0;

    const EXPIRE_DATE = 86400; // 订单过期时间 秒

    protected $table = 'order';
    protected $guarded = [];

    protected $primaryKey = 'order_id';

    public $timestamps = false;

    protected $casts = [
        'customer_id'     => 'int',
        'order_status_id' => 'int'
    ];

    /**
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function orderProducts()
    {
        return $this->hasMany(OrderProduct::class, 'order_id', 'order_id');
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function orderOptions()
    {
        return $this->hasMany(OrderOption::class, 'order_id', 'order_id');
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function orderTotals()
    {
        return $this->hasMany(OrderTotal::class, 'order_id', 'order_id');
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\HasOne
     */
    public function orderHistoryByPayment()
    {
        return $this->hasOne(OrderHistory::class, 'order_id', 'order_id')
            ->whereIn('order_status_id', OrderStatus::getOrderStatusIdToBeShipped());
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\HasOne
     */
    public function orderHistoryByComplete()
    {
        return $this->hasOne(OrderHistory::class, 'order_id', 'order_id')
            ->whereIn('order_status_id', OrderStatus::getOrderStatusIdsToBeEvaluate());
    }

    /**
     * 返回订单总额
     *
     * @return \Illuminate\Database\Eloquent\Relations\HasOne
     */
    public function orderTotalByTotal()
    {
        return $this->hasOne(OrderTotal::class, 'order_id', 'order_id')
            ->where('code', OrderTotal::ORDER_TOTAL_CODE_TOTAL);
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function orderStatusByLanguage()
    {
        return $this->belongsTo(OrderStatus::class, 'order_status_id', 'order_status_id')
            ->where('language_id', AppEnv::languageId());
    }

    /**
     * @deprecated
     * @param $out_trade_no
     * @return mixed
     */
    public static function transformOrderId($out_trade_no)
    {
        // time_id
        $explode = explode('_', $out_trade_no);
        return end($explode); // order_id
    }

    /**
     * @param $trade_no
     * @return Order|null
     */
    public static function findOrderUnpaidByTradeNo(string $trade_no): ?Order
    {
        return $order = (new Order)->where([
            ['trade_no', $trade_no],
            ['order_status_id', OrderStatus::ORDER_STATUS_ID_DEFAULT]
        ])->first();
    }

    /**
     * @used-by filterOrderStatusIds()
     *
     * @param Builder $query
     * @param $order_status_ids
     * @return Builder
     */
    public function scopeFilterOrderStatusIds(Builder $query, $order_status_ids)
    {
        return $query->whereIn('order_status_id', $order_status_ids);
    }

    /**
     * @used-by filterIsToBeEvaluate()
     *
     * @param Builder $query
     * @param string $order_flow_status_id
     * @return Builder
     */
    public function scopeFilterIsToBeEvaluate(Builder $query, $order_flow_status_id)
    {
        $is_to_be_evaluate = ((int)$order_flow_status_id === OrderFlowStatus::ORDER_FLOW_STATUS_ID_TO_BE_EVALUATE);

        if (!$is_to_be_evaluate) return $query;

        return $query->whereHas('orderProducts', function(Builder $query){
            $query->doesntHave('review');
//                ->doesntHave('returnProduct'); // todo 待评价订单不用过滤有售后的。
        });
    }

    /**
     * @used-by filterCancelOrder()
     *
     * @param Builder $query
     * @return Builder|\Illuminate\Database\Query\Builder
     */
    public function scopeFilterCancelOrder(Builder $query)
    {
        return $query->whereNotIn('order_status_id', OrderStatus::ORDER_STATUS_ID_CANCEL_MAP);

    }

    /**
     *  @used-by filterLogistics()
     *
     * @param Builder $query
     * @return Builder|\Illuminate\Database\Query\Builder
     */
    public function scopeFilterLogistics(Builder $query)
    {
        return $query->where('shipping_shipper_code', '<>', '')
            ->where('shipping_logistic_code', '<>', '');
    }

    /**
     * @used-by expire_date
     * @return false|int
     */
    public function getExpireDateAttribute()
    {
        $add_date = $this->attributes['date_added'];

        $expire_date = self::EXPIRE_DATE;

        return strtotime("$add_date +$expire_date second");
    }

    /**
     * @param $order_id
     * @return Order|Model|null|object
     */
    public static function getOrder($order_id)
    {
        $order = (new self)->where('order_id', $order_id)
            ->where('customer_id', Guard::customer()->customer_id)
            ->first();

        return $order;
    }

    /**
     * @param Order $order
     * @return bool
     */
    public static function isHasLogistics(Order $order)
    {
        $has_logistics = ($order->shipping_shipper_code && $order->shipping_logistic_code);

        return $has_logistics;
    }

    /**
     * @param Order $order
     * @return bool
     */
    public static function isHasReview(Order $order)
    {
        $has_review_count = $order->orderProducts()
            ->has('review')
            ->count();

        return (bool)($order->orderProducts->count() === $has_review_count);
    }

    /**
     * 验证未付款订单是否过期
     *
     * @param Order $order
     * @return bool
     */
    public static function validateOrderIsExpire(Order $order)
    {
        /** @var Carbon $date_added */
        $date_added = new Carbon($order->date_added);

        // 有效期是一天
        $date_expired = $date_added->addDay();

        $is_expired = $date_expired->gte(Carbon::now());

        return $is_expired;
    }

    /**
     * 验证订单是否已经付款了
     *
     * @param Order $order
     * @return bool
     */
    public static function validateOrderIsPayment(Order $order)
    {
        $order_status_id = $order->order_status_id;

        $is_payment = ($order_status_id === OrderStatus::ORDER_STATUS_ID_DEFAULT) ? true : false;

        return $is_payment;
    }

    public function isOrderStatusProcessing(): bool
    {
        return in_array($this->order_status_id, OrderStatus::getOrderStatusIdToBeReceived());
    }

    public function isOrderStatusUnpaid(): bool
    {
        return $this->order_status_id === OrderStatus::ORDER_STATUS_ID_DEFAULT;
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\HasOne
     */
    public function orderAutoSign()
    {
        return $this->hasOne(OrderAutoSign::class, 'order_id', 'order_id');
    }
}
